/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * MediaOctopusPlayer.java
 *
 * Created on Apr 29, 2011, 11:30:12 AM
 */
package edu.usc.cs576.mediaoctopusplayer;

import edu.usc.cs576.lib.Action;
import edu.usc.cs576.lib.MediaObject;
import edu.usc.cs576.lib.Monitor.LoadingMonitor;
import edu.usc.cs576.lib.mediaObject.Audio;
import edu.usc.cs576.lib.mediaObject.Image;
import edu.usc.cs576.lib.mediaObject.Track;
import edu.usc.cs576.lib.mediaObject.Video;
import edu.usc.cs576.lib.xml.XMLReader;
import edu.usc.cs576.mediaoctopusplayer.data.Data;
import edu.usc.cs576.mediaoctopusplayer.panel.ImportDialog;
import edu.usc.cs576.mediaoctopusplayer.settings.Settings;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;

/**
 *
 * @author haoxu
 */
public class MediaOctopusPlayer extends javax.swing.JFrame {

    boolean played = false;

    /** Creates new form MediaOctopusPlayer */
    public MediaOctopusPlayer() {

        initComponents();

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        openFileChooser = new javax.swing.JFileChooser();
        canvasPanel = new javax.swing.JPanel();
        jMenuBar = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        openMenuItem = new javax.swing.JMenuItem();
        exitMenuItem = new javax.swing.JMenuItem();
        aboutMenuItem = new javax.swing.JMenu();
        jMenuItem1 = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        canvasPanel.setBackground(new java.awt.Color(102, 102, 102));
        canvasPanel.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                canvasPanelMouseMoved(evt);
            }
        });

        org.jdesktop.layout.GroupLayout canvasPanelLayout = new org.jdesktop.layout.GroupLayout(canvasPanel);
        canvasPanel.setLayout(canvasPanelLayout);
        canvasPanelLayout.setHorizontalGroup(
            canvasPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 658, Short.MAX_VALUE)
        );
        canvasPanelLayout.setVerticalGroup(
            canvasPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 410, Short.MAX_VALUE)
        );

        jMenu1.setText("File");

        openMenuItem.setText("Open");
        openMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openMenuItemActionPerformed(evt);
            }
        });
        jMenu1.add(openMenuItem);

        exitMenuItem.setText("Exit");
        exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitMenuItemActionPerformed(evt);
            }
        });
        jMenu1.add(exitMenuItem);

        jMenuBar.add(jMenu1);

        aboutMenuItem.setText("Help");

        jMenuItem1.setText("About");
        aboutMenuItem.add(jMenuItem1);

        jMenuBar.add(aboutMenuItem);

        setJMenuBar(jMenuBar);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(canvasPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(canvasPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMenuItemActionPerformed
        // TODO add your handling code here:
        int returnValue = openFileChooser.showOpenDialog(this);

        if (returnValue == JFileChooser.APPROVE_OPTION) {
            File file = openFileChooser.getSelectedFile();

            XMLReader reader = new XMLReader(file.getName(), file.getAbsolutePath());
            reader.init();

            this.setSize(reader.getWidth(), reader.getHeight() + jMenuBar.getHeight());
            canvasPanel.setSize(reader.getWidth(), reader.getHeight());

            Data.setVideo(reader.getVideo());
            Data.setAudio(reader.getAudio());
            Data.setImages(reader.getImages());
            Data.setTracks(reader.getTracks());

            importDialog = new ImportDialog(this, true);

            importDialog.getTitleLabel().setText("Import Content from " + file.getName());
            importDialog.setTitle("Importing");

            ImportTask itask = new ImportTask();
            itask.addPropertyChangeListener(importDialog);
            new Thread() {

                @Override
                public void run() {
                    importDialog.setVisible(true);
                }
            }.start();

            itask.execute();
        }
    }//GEN-LAST:event_openMenuItemActionPerformed

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        // TODO add your handling code here:
        System.exit(0);
    }//GEN-LAST:event_exitMenuItemActionPerformed

    private void canvasPanelMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_canvasPanelMouseMoved
        // TODO add your handling code here:
        canvasPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    }//GEN-LAST:event_canvasPanelMouseMoved

    private void JLabelClick(MouseEvent evt) {
        JLabel label = (JLabel) evt.getSource();
        MediaObject object = Data.getData().get(label);
        ArrayList<Action> actions = object.getActions();

        for (int i = 0; i < actions.size(); i++) {
            Action action = actions.get(i);
            switch (action.getActionNumber()) {
                case 1:
                    try {
                        play();
                    } catch (UnsupportedAudioFileException ex) {
                        Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    break;
                case 2:
                    pause();
                    break;
                case 3:
                    stop();
                    break;
                case 7:
                    link(action.getParam1());
                    break;
                default:
            }
        }
    }

    public void JLabelMove(MouseEvent evt) {
        JLabel label = (JLabel) evt.getSource();
        ArrayList<Action> actions = Data.getData().get(label).getActions();
        boolean link = false;
        for (int i = 0; i < actions.size(); i++) {
            if (actions.get(i).getActionNumber() == 7) {
                canvasPanel.setCursor(new Cursor(Cursor.HAND_CURSOR));
                link = true;
                break;
            }
        }
        if (!link) {
            canvasPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new MediaOctopusPlayer().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu aboutMenuItem;
    private javax.swing.JPanel canvasPanel;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenuBar jMenuBar;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JFileChooser openFileChooser;
    private javax.swing.JMenuItem openMenuItem;
    // End of variables declaration//GEN-END:variables
    private ImportDialog importDialog;

    private void play() throws UnsupportedAudioFileException {

        if (!Settings.IS_PLAYING) {
            if (Data.getAudio() != null) {
                System.out.println("Settings.IS_PLAYING: " + Settings.IS_PLAYING);
                System.out.println(Settings.IS_PAUSED);
                System.out.println(played);
                if (Settings.IS_PLAYING == false && Settings.IS_PAUSED == false&&played==true) {

                    try {
                        Audio au = new Audio(Data.getAudio().getFilepath());
                        Data.setAudio(au);
                        au.load2();
                        au.show2();
                    } catch (IOException ex) {
                        Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } else {
                    try {
                        Data.getAudio().show2();
                    } catch (IOException ex) {
                        Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                played = true;
            }
        }
        Settings.IS_PLAYING = true;

        if (Data.getVideo() != null) {
            new Thread() {

                boolean isPlayaudio = true;

                @Override
                public void run() {
                    while (Settings.IS_PLAYING) {
                        try {
                            if (Settings.FRAME_NUM < 1 || Settings.FRAME_NUM > Data.getVideo().getImages().size()) {
                                //when movie reaches the end
                                Settings.FRAME_NUM = 1;
                                JLabel videoLabel = Data.getDisplay().get(Data.getVideo());
                                videoLabel.setIcon(new ImageIcon(Data.getVideo().getImages().get(0).getImage()));
                                for (int i = 0; i < Data.getImages().size(); i++) {
                                    Image image = Data.getImages().get(i);
                                    if (image.getStartFrame() > 0) {
                                        if (image.getStartFrame() > 1) {
                                            Data.getDisplay().get(image).setVisible(false);
                                        } else {
                                            Data.getDisplay().get(image).setVisible(true);
                                        }
                                    } else {
                                        Data.getDisplay().get(image).setVisible(true);
                                    }
                                }
                                Settings.IS_PLAYING = false;
                                continue;
                            }

                            //normal playing
                            //update video
                            JLabel videoLabel = Data.getDisplay().get(Data.getVideo());
                            videoLabel.setIcon(new ImageIcon(Data.getVideo().getImages().get(Settings.FRAME_NUM - 1).getImage()));

                            double rate = (double) Data.getAudio().getf2() / (double) Data.getVideo().getImages().size();
                            double real_rate = (double) Data.getAudio().getPos2() / Settings.FRAME_NUM;
                            System.out.println(rate);
                            System.out.println(real_rate);

                            boolean change = false;
                            if (real_rate > 745 && isPlayaudio == true) {
                                System.out.println("1111111111111");
                                System.out.println(isPlayaudio);
                                isPlayaudio = false;
                                System.out.println(isPlayaudio);
                                Data.getAudio().pause2();

                                change = true;
                            }
                            if (real_rate < 720 && isPlayaudio == false) {
                                System.out.println("22222222222");
                                try {
                                    Data.getAudio().show2();
                                } catch (IOException ex) {
                                    Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                                }
                                isPlayaudio = true;
                            }
                            Settings.FRAME_NUM++;
                            //update images
                            for (int i = 0; i < Data.getImages().size(); i++) {
                                Image image = Data.getImages().get(i);
                                if (image.getStartFrame() > 0) {
                                    if (image.getStartFrame() <= Settings.FRAME_NUM && image.getEndFrame() >= Settings.FRAME_NUM) {
                                        Data.getDisplay().get(image).setVisible(true);
                                    } else {
                                        Data.getDisplay().get(image).setVisible(false);
                                    }
                                }
                            }

                            //update tracks
                            for (int i = 0; i < Data.getTracks().size(); i++) {
                                Track track = Data.getTracks().get(i);
                                if (track.getStartFrame() >= 0) {
                                    if (track.getStartFrame() <= Settings.FRAME_NUM && track.getEndFrame() >= Settings.FRAME_NUM) {
                                        Data.getDisplay().get(track).setVisible(true);
                                        Point p = track.getLocation(Settings.FRAME_NUM);
                                        Data.getDisplay().get(track).setLocation(p);
                                    } else {
                                        Data.getDisplay().get(track).setVisible(false);
                                    }
                                } else {
                                    Data.getDisplay().get(track).setVisible(true);
                                    Point p = track.getLocation(Settings.FRAME_NUM);
                                    Data.getDisplay().get(track).setLocation(p);
                                }
                            }

                            Thread.sleep(1000 / 30);
                        } catch (InterruptedException ex) {
                            Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
            }.start();
        }


    }

    private void pause() {
        Settings.IS_PLAYING = false;
        Settings.IS_PAUSED = true;
        if (Data.getAudio() != null) {
            // System.out.println("11111111111");
            Data.getAudio().pause2();
        }
    }

    private void stop() {
        Settings.IS_PLAYING = false;
        Settings.FRAME_NUM = 1;
        Settings.IS_PAUSED = false;
        if (Data.getAudio() != null) {
            Data.getAudio().stop2();
        }

    }

    private void link(String param1) {
        OpenURLThread thread = new OpenURLThread(param1, this);
        thread.start();
    }

    class OpenURLThread extends Thread {

        JFrame frame;
        String url;

        public OpenURLThread(String url, JFrame frame) {
            this.url = url;
            this.frame = frame;
        }

        @Override
        public void run() {
            try {

                if (!java.awt.Desktop.isDesktopSupported()) {
                    JOptionPane.showMessageDialog(frame, "JAVA SE 6 is required to open the link");
                    return;
                }
                java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
                if (!desktop.isSupported(java.awt.Desktop.Action.BROWSE)) {
                    JOptionPane.showMessageDialog(frame, "Desktop doesn't support the browser function");
                    return;
                }
                desktop.browse(new URI(url));
            } catch (IOException ex) {
                Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
            } catch (URISyntaxException ex) {
                Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    class ImportTask extends SwingWorker<Void, Void> {

        @Override
        protected Void doInBackground() {
            LoadingMonitor.LOAD_SIZE = 0;
            Data.getVideo().prepare();

            new Thread() {

                @Override
                public void run() {
                    try {
                        //load and resize images
                        for (int i = 0; i < Data.getImages().size(); i++) {
                            Image image = Data.getImages().get(i);
                            image.load();

                            BufferedImage before = (BufferedImage) image.getImage();
                            int w = image.getResize_x();
                            int h = image.getResize_y();
                            BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
                            AffineTransform at = new AffineTransform();
                            at.scale((double) w / (double) image.getWidth(), (double) h / (double) image.getHeight());
                            AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
                            after = scaleOp.filter(before, after);

                            image.setImage(after);
                            image.setWidth(w);
                            image.setHeight(h);
                        }

                        //load auido
                        Data.getAudio().load2();

                        //load video
                        Video video = Data.getVideo();
                        video.load();

                        //resize video
                        for (int i = 0; i < video.getImages().size(); i++) {
                            Image vimage = video.getImages().get(i);
                            /**this part is using affinetransform class
                            BufferedImage vbefore = (BufferedImage)vimage.getImage();
                            int w = video.getResize_x();
                            int h = video.getResize_y();
                            BufferedImage vafter = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
                            AffineTransform at = new AffineTransform();
                            at.scale((double) w / (double) video.getWidth(), (double) h / (double) video.getHeight());
                            AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
                            vafter = scaleOp.filter(vbefore, vafter);
                             */
                            java.awt.Image vafter = null;

                            int w = video.getResize_x();
                            int h = video.getResize_y();

                            if (vimage.getWidth() != w || vimage.getHeight() != h) {
                                vafter = vimage.getImage().getScaledInstance(w, h, java.awt.Image.SCALE_SMOOTH);
                                vimage.setWidth(w);
                                vimage.setHeight(h);
                                vimage.setImage(vafter);
                            }
                        }

                    } catch (UnsupportedAudioFileException ex) {
                        Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IOException ex) {
                        Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(MediaOctopusPlayer.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }.start();

            while (LoadingMonitor.LOAD_SIZE < LoadingMonitor.TOTAL_SIZE
                    || !LoadingMonitor.LOAD_FINISHED) {
                if (!LoadingMonitor.LOAD_FINISHED) {
                    int progress = (int) (LoadingMonitor.LOAD_SIZE / LoadingMonitor.TOTAL_SIZE * 100);
                    setProgress(progress);
                }
            }

            return null;
        }

        @Override
        public void done() {
            if (Data.getVideo() != null && Data.getVideo().getImages() != null) {
                Toolkit.getDefaultToolkit().beep();

                Settings.IS_VIDEO_IMPORTED = true;

                //update image UI
                for (int i = 0; i < Data.getImages().size(); i++) {
                    Image image = Data.getImages().get(i);

                    JLabel label = new JLabel();
                    label.setSize(image.getWidth(), image.getHeight());
                    label.setIcon(new ImageIcon(image.getImage()));
                    label.setLocation(image.getX(), image.getY());
                    label.addMouseListener(new MouseListener() {

                        public void mouseClicked(MouseEvent e) {
                            JLabelClick(e);
                        }

                        public void mousePressed(MouseEvent e) {
                        }

                        public void mouseReleased(MouseEvent e) {
                        }

                        public void mouseEntered(MouseEvent e) {
                        }

                        public void mouseExited(MouseEvent e) {
                        }
                    });

                    label.addMouseMotionListener(new MouseMotionListener() {

                        public void mouseDragged(MouseEvent e) {
                        }

                        public void mouseMoved(MouseEvent e) {
                            JLabelMove(e);
                        }
                    });

                    canvasPanel.add(label);

                    Data.getData().put(label, image);
                    Data.getDisplay().put(image, label);
                }

                //update trackUI
                for (int i = 0; i < Data.getTracks().size(); i++) {
                    Track track = Data.getTracks().get(i);

                    JLabel label = new JLabel();
                    label.setSize(track.getWidth(), track.getHeight());
                    label.setLocation(track.getKeyframes().get(0).getPosition_x(), track.getKeyframes().get(0).getPosition_y());
                    label.addMouseListener(new MouseListener() {

                        public void mouseClicked(MouseEvent e) {
                            JLabelClick(e);
                        }

                        public void mousePressed(MouseEvent e) {
                        }

                        public void mouseReleased(MouseEvent e) {
                        }

                        public void mouseEntered(MouseEvent e) {
                        }

                        public void mouseExited(MouseEvent e) {
                        }
                    });

                    label.addMouseMotionListener(new MouseMotionListener() {

                        public void mouseDragged(MouseEvent e) {
                        }

                        public void mouseMoved(MouseEvent e) {
                            JLabelMove(e);
                        }
                    });

                    canvasPanel.add(label);

                    Data.getData().put(label, track);
                    Data.getDisplay().put(track, label);
                }


                //update video UI
                Video video = Data.getVideo();
                if (video != null) {
                    JLabel videoLabel = new JLabel();
                    videoLabel.setSize(video.getResize_x(), video.getResize_y());
                    videoLabel.setLocation(video.getX(), video.getY());
                    videoLabel.setIcon(new ImageIcon(video.getImages().get(0).getImage()));

                    canvasPanel.add(videoLabel);

                    video.setWidth(video.getResize_x());
                    video.setHeight(video.getResize_y());

                    Data.getData().put(videoLabel, video);
                    Data.getDisplay().put(video, videoLabel);
                }

                Settings.FRAME_NUM = 1;

                importDialog.setVisible(false);
                canvasPanel.getParent().repaint();
            }
        }
    }
}